from typing import Dict, List, Optional, Tuple, Union

from ...core.datatypes import Entity
from enum import Enum

# from ..format_utils import *
from .BaseOutputFormatter import BaseOutputFormatter
from ..format_utils import format_str_list_to_a_string


class Language(Enum):
    EN = "en"


class EntityFormatter:

    available_languages = [Language.EN.value]
    patterns = {
        Language.EN.value: "{0} is {1} {2}",  # value is a/and label
    }

    vowel_letters = ["a", "e", "i", "o", "u"]

    # def __init__(self, sep: str = "<sep>"):
    #     super().__init__(sep)
    sep = "<sep>"

    @classmethod
    def from_relations(
        cls, relations: Optional[List[Dict[str, List[str]]]], language: str = "en"
    ) -> Optional[str]:
        instrances = []

        for r in relations:
            instrances.extend(cls.from_relation_triple(r, language))

        answer = ", ".join(instrances) + "."
        return answer

    @classmethod
    def from_relation_triple(
        cls, relation: Optional[Dict[str, List[str]]], language: str = "en"
    ) -> Optional[str]:

        if language not in cls.available_languages:
            raise ValueError(
                f"Expected language to be one of {cls.available_languages}"
            )

        if relation is None:
            return None

        answers = []

        head = relation["head"]
        tail = relation["tail"]

        # head 和 tail 必须是有name, type两个属性的字典
        if (
            "name" not in head
            or "type" not in head
            or "name" not in tail
            or "type" not in tail
        ):
            raise ValueError("Expected head and tail to have name and type attributes")

        for entity in [head, tail]:
            # if entity["type"] in ["NA"]:
            if entity["type"] in ["NA", "na", "", None]:
                entity_type = "entity"
            else:
                entity_type = entity["type"].lower()

            if entity_type[0] in cls.vowel_letters:
                answers.append(
                    cls.patterns[language].format(entity["name"], "an", entity_type)
                )
            else:
                answers.append(
                    cls.patterns[language].format(entity["name"], "a", entity_type)
                )

        return answers

    @classmethod
    def from_spans(
        cls,
        context: str,
        entity_spans: List[Tuple[int, int, str]],
        language: str = "en",
    ) -> str:
        answers = []

        if language not in cls.available_languages:
            raise ValueError(
                f"Expected language to be one of {cls.available_languages}"
            )

        for span in entity_spans:

            start, end, label = span[0], span[1], span[2]
            value = context[start:end]

            if value.lower().startswith("a"):
                answers.append(cls.patterns[language].format(value, "an", label))
            else:
                answers.append(cls.patterns[language].format(value, "a", label))

        answer = ", ".join(answers) + "."

        return answer

    @classmethod
    def format_entities(
        cls,
        entities: List[Entity],
        language: str = "en",
        **kwargs,
    ) -> str:
        """将实体列表格式化为字符串
        str: 使用[sep]连接的实体字符串，最后使用句号.结束。


        Args:
            entities (List[Entity]): 实体列表
            language (str, optional):

        Returns:
            str: 格式化后的字符串，形如 "xxx is a/an label, yyy is a/an label."
        """
        answers = []

        if kwargs["template_order"] == 2:
            format_fn = cls.format_entity_for_simple_template
        else:
            format_fn = cls.format_entity_to_sentence

        answers = list(map(lambda x: format_fn(x), entities))

        return format_str_list_to_a_string(answers, sep=cls.sep)

    @classmethod
    def format_entity_to_sentence(cls, entity: Entity, language: str = "en") -> str:
        """将Entity实例格式化为形如 xxx is a/an person 的句子

        Args:
            entity (Entity): Entity实例
            language (str, optional): 格式化语言. Defaults to "en".

        Returns:
            str: 格式化后的字符串， xx is a/an label
        """
        entity_type = entity.type.lower()

        if entity_type[0] in cls.vowel_letters:
            return cls.patterns[language].format(entity.name, "an", entity_type)
        return cls.patterns[language].format(entity.name, "a", entity_type)

    @classmethod
    def format_entity_for_simple_template(
        cls,
        entity: Entity,
    ) -> str:
        """将实体格式化为一个字符串

        Args:
            entity (Entity): Entity实例
        Returns:
            str: 使用[sep]连接的实体字符串，形如 "xxx (entity_label)"
        """
        return f"{entity.name} ({str.lower(entity.type)})"
